package org.dei.test.llqruntime;

import java.util.*;
import org.dei.perla.parser.clauses.*;
import org.dei.perla.parser.datastructures.*;
import org.dei.perla.parser.expressions.*;
import org.dei.perla.parser.statements.*;
import org.dei.perla.parser.util.Duration;
import org.dei.perla.sys.llqruntime.DataCollector;
import org.dei.perla.sys.llqruntime.datastructures.*;

/**
 * Fornisce metodi per analizzare Query a qualsiasi livello
 * @author Camplani, Fortunato, Marelli, Rota et al. 
 */
public class QueryAnalyzerEnhanced {
	
	/**
	 * Restituisce l'oggetto che rappresenta una singola LLQ nel contesto dell'esecuzione di basso livello
	 * @param parQuery il formato Java della query di PerLa
	 * @return Una lista dei singoli LLQ che compongono la Query
	 */
	public static ArrayList<LLQEnvironment> createLLQEnvironments(Query parQuery) {
		
		//TODO LLQEnvironment è costruito con null DC -> Info doppia!
		
		ArrayList<LLQEnvironment> tArrayList = new ArrayList<LLQEnvironment>();
		LLQEnvironment tEnvironment;

		for (int tCounter = 0;tCounter<=getLLQueriesNumber(parQuery);tCounter++) {
				
			tEnvironment = new LLQEnvironment(createDataCollectors(parQuery,tCounter),getQueryInformation(parQuery,tCounter),new Buffer());
			tArrayList.add(tEnvironment);	
			
			//Se DataCollectorV2 dovesse diventare effettivo
			
			//1. per ogni LLQ del parser:
			//2. creati LLQInformation
			//3. crea i DC e linkali al LLQInformation di cui al punto 2
			//4. crea LLQEnvironment con dentro un buffer
			//5. aggiungi ad un Arraylist, cicla ancora, return();
			
		}
		
		return tArrayList;
	}
	
	private static ArrayList<DataCollector> createDataCollectors(Query parQuery, int index) {
		
		return new ArrayList<DataCollector>();
	}
	
	/**
	 * Costruisce l'oggetto che contiene le informazioni generali di una Query
	 * @param parQuery il formato Java della query di PerLa
	 * @param index
	 * @return
	 */
	private static LLQInformations getQueryInformation(Query parQuery, int index) {
		
		LLQInformations tInfo = new LLQInformations(getWhereCondition(parQuery,index),getSamplingTable(parQuery,index),null);
		return tInfo;
	}
	
	/**
	 * Restituisce il numero di LLQ che compongono la query di PerLa
	 */
	private static int getLLQueriesNumber(Query parQuery) {
		
		return parQuery.getLLStatements().size();
	}
	
	/**
	 * Metodo che restituisce la condizione WHERE
	 * @return il nodo che rappresenta la condizione
	 */
	private static Node getWhereCondition(Query parQuery,int index) {
		
		return parQuery.getLLStatements().get(index).getSamplingClause().getWhereClause().getCondition();
		
	}
	
	/**
	 * Metodo che restituisce la struttura dati per decidere la frequenza di campionamento
	 * @return La struttura dati
	 */
	private static SamplingFrequenciesTable getSamplingTable(Query parQuery,int index) {
		
		SamplingClause tClause = parQuery.getLLStatements().get(index).getSamplingClause();
		
		
		
		if (tClause instanceof SamplingTimeBased) {
			
			ArrayList<FrequencyRecord> tArrayList = new ArrayList<FrequencyRecord>();
			
			for (SamplingIfEvery tSampling : ((SamplingTimeBased) tClause).getPeriods()) {
				
				Duration tDuration = null;
				
				try {
					
					tDuration = new Duration(tSampling.getSamplingRate().getResult().getValueFloat(),tSampling.getTimeUnit());
				} catch (Exception e) {
					
					e.printStackTrace();
				}
				tArrayList.add(new FrequencyRecord(tSampling.getCondition(),tDuration));
				//tArrayList.add(new FrequencyRecord(tSampling.getCondition(),tNodeComparison,tDuration));	
								
			}
		return new SamplingFrequenciesTable(tArrayList,((SamplingTimeBased) tClause).getOperation());	
		
		}else return null;
		
	}
	
	/**
	 * Restituisce la struttura del buffer di uscita di una query
	 */
	public static QueryRecordStructure getOutputBufferStructure(Query parQuery, int index) {
				
		StatementFieldList tFieldList = parQuery.getLLStatements().get(index).getFields();
		QueryRecordStructure tQueryRecordStructure = new QueryRecordStructure();
		
		for (Field tField : tFieldList) {
			
			tQueryRecordStructure.addFieldStructure(tField.getName(), tField.getType().getFieldTypeClass());			
		}
		
		return tQueryRecordStructure;
	}
}
